package com.xyh.builder;

import com.xyh.bean.Constants;
import com.xyh.bean.FieldInfo;
import com.xyh.bean.TableInfo;
import com.xyh.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public class BuildController {
    private static final Logger logger = LoggerFactory.getLogger(BuildController.class);

    public static void execute(TableInfo tableInfo) {
        File controllerDir = new File(Constants.PATH_CONTROLLER);
        if (!controllerDir.exists() && !controllerDir.mkdirs()) {
            logger.error("创建Controller目录失败: {}", Constants.PATH_CONTROLLER);
            return;
        }

        File controllerFile = new File(controllerDir, tableInfo.getBeanName() + Constants.SUFFIX_CONTROLLER + ".java");

        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(controllerFile), StandardCharsets.UTF_8))) {

            // 1. 基础结构
            writeBaseStructure(bw, tableInfo);

            // 2. 核心方法
            writeCoreMethods(bw, tableInfo);

            // 3. 主键操作方法
            writeKeyOperations(bw, tableInfo);

            bw.write("}");
            logger.info("生成Controller成功: {}", controllerFile.getAbsolutePath());
        } catch (Exception e) {
            logger.error("生成Controller失败: 表名={}", tableInfo.getTableName(), e);
        }
    }

    private static void writeBaseStructure(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        // 包声明和导入
        bw.write("package " + Constants.PACKAGE_CONTROLLER + ";\n\n");
        bw.write("import " + Constants.PACKAGE_VO + ".ResultVO;\n");
        bw.write("import " + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + ";\n");
        bw.write("import " + Constants.PACKAGE_PARAM + "." + tableInfo.getBeanParamName() + ";\n");
        bw.write("import " + Constants.PACKAGE_SERVICE + "." + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE + ";\n");
        bw.write("import org.springframework.web.bind.annotation.*;\n");
        bw.write("import jakarta.annotation.Resource;\n");
        bw.write("import java.util.List;\n\n");

        // 类注释
        bw.write("/**\n");
        bw.write(" * " + tableInfo.getComment() + "控制器\n");
        bw.write(" */\n");

        // 类定义
        bw.write("@RestController\n");
        bw.write("@RequestMapping(\"/" + StringUtils.lowerCaseFirstLetter(tableInfo.getBeanName()) + "\")\n");
        bw.write("public class " + tableInfo.getBeanName() + Constants.SUFFIX_CONTROLLER + " {\n\n");

        // 服务注入
        bw.write("\t@Resource\n");
        bw.write("\tprivate " + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE + " service;\n\n");
    }

    private static void writeCoreMethods(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        // 分页查询
        writeMethod(bw,
                "@PostMapping(\"/list\")",
                "public ResultVO list(@RequestBody " + tableInfo.getBeanParamName() + " param)",
                "return ResultVO.ok(service.findListByParam(param));");

        // 新增
        writeMethod(bw,
                "@PostMapping",
                "public ResultVO add(@RequestBody " + tableInfo.getBeanName() + " entity)",
                "return ResultVO.ok(service.add(entity));");

        // 批量新增
        writeMethod(bw,
                "@PostMapping(\"/batch\")",
                "public ResultVO batchAdd(@RequestBody List<" + tableInfo.getBeanName() + "> list)",
                "return ResultVO.ok(service.batchAdd(list));");
    }

    private static void writeKeyOperations(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        for (Map.Entry<String, List<FieldInfo>> entry : tableInfo.getKeyIndexMap().entrySet()) {
            List<FieldInfo> keyFields = entry.getValue();
            String methodName = buildMethodName(keyFields);
            String pathParams = buildPathParams(keyFields);
            String methodParams = buildMethodParams(keyFields);

            // 根据主键查询
            writeMethod(bw,
                    "@GetMapping(\"/" + pathParams + "\")",
                    "public ResultVO getBy" + methodName + "(" + methodParams + ")",
                    "return ResultVO.ok(service.findBy" + methodName + "(" + getParamNames(keyFields) + "));");

            // 根据主键更新
            writeMethod(bw,
                    "@PutMapping(\"/" + pathParams + "\")",
                    "public ResultVO updateBy" + methodName + "(@RequestBody " + tableInfo.getBeanName() + " entity, " + methodParams + ")",
                    "return ResultVO.ok(service.updateBy" + methodName + "(entity, " + getParamNames(keyFields) + "));");

            // 根据主键删除
            writeMethod(bw,
                    "@DeleteMapping(\"/" + pathParams + "\")",
                    "public ResultVO deleteBy" + methodName + "(" + methodParams + ")",
                    "return ResultVO.ok(service.deleteBy" + methodName + "(" + getParamNames(keyFields) + "));");
        }
    }

    private static void writeMethod(BufferedWriter bw, String mapping, String signature, String body) throws IOException {
        bw.write("\t" + mapping + "\n");
        bw.write("\t" + signature + " {\n");
        bw.write("\t\t" + body + "\n");
        bw.write("\t}\n\n");
    }

    private static String buildMethodName(List<FieldInfo> keyFields) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keyFields.size(); i++) {
            sb.append(StringUtils.upperCaseFirstLetter(keyFields.get(i).getPropertyName()));
            if (i < keyFields.size() - 1) {
                sb.append("And");
            }
        }
        return sb.toString();
    }

    private static String buildPathParams(List<FieldInfo> keyFields) {
        StringBuilder sb = new StringBuilder();
        for (FieldInfo field : keyFields) {
            sb.append("{" + field.getPropertyName() + "}/");
        }
        return sb.substring(0, sb.length() - 1);
    }

    private static String buildMethodParams(List<FieldInfo> keyFields) {
        StringBuilder sb = new StringBuilder();
        for (FieldInfo field : keyFields) {
            sb.append("@PathVariable " + field.getJavaType() + " " + field.getPropertyName() + ", ");
        }
        return sb.substring(0, sb.length() - 2);
    }

    private static String getParamNames(List<FieldInfo> keyFields) {
        StringBuilder sb = new StringBuilder();
        for (FieldInfo field : keyFields) {
            sb.append(field.getPropertyName() + ", ");
        }
        return sb.substring(0, sb.length() - 2);
    }
}